<template>
	<div class="flow-chart-container" :style="containerStyle">
		<div class="flow-chart-header" v-if="showHeader">
			<div class="header-content">
				<div class="header-left">
					<h3 class="chart-title">{{ title }}</h3>
					<div class="chart-info">
						<span class="info-badge">{{ layoutInfo.nodeCount }} 个节点</span>
						<span v-if="nodesDraggable" class="info-badge draggable-hint">
							<el-icon><User /></el-icon>
							可拖拽
						</span>
					</div>
				</div>
				<div class="header-right">
					<div class="zoom-level">{{ (zoomLevel * 100).toFixed(0) }}%</div>
					<el-button-group size="small">
						<el-button @click="handleFitView" title="适应视图">
							<el-icon>
								<FullScreen />
							</el-icon>
							适应
						</el-button>
						<el-button @click="() => zoomToLevel(1)" title="重置缩放">
							<el-icon>
								<Document />
							</el-icon>
							重置
						</el-button>
						<el-button @click="handleZoomOut" title="缩小">
							<el-icon>
								<Minus />
							</el-icon>
						</el-button>
						<el-button @click="handleZoomIn" title="放大">
							<el-icon>
								<Plus />
							</el-icon>
						</el-button>
					</el-button-group>
				</div>
			</div>
		</div>

		<div class="flow-chart-wrapper" ref="chartWrapper">
			<div class="flow-chart-inner" v-if="processedNodes.length > 0">
				<VueFlow
					ref="vueFlowRef"
					:nodes="processedNodes"
					:edges="processedEdges"
					class="flow-chart"
					:nodes-draggable="nodesDraggable"
					:nodes-connectable="false"
					:nodes-selectable="true"
					:nodes-focusable="true"
					:edges-updatable="false"
					:edges-reconnectable="false"
					:edges-focusable="true"
					:zoom-on-scroll="true"
					:zoom-on-pinch="true"
					:zoom-on-double-click="true"
					:pan-on-scroll="false"
					:pan-on-scroll-mode="PanOnScrollMode.Free"
					:pan-on-scroll-speed="0.5"
					:pan-on-drag="true"
					:selection-on-drag="false"
					:multiselection-key-code="'Meta'"
					:delete-key-code="'Delete'"
					:default-zoom="1"
					:min-zoom="0.2"
					:max-zoom="4"
					:zoom-duration="300"
					:fit-view-on-init="true"
					:fit-view-options="{ padding: 0.1, duration: 300 }"
					:translate-extent="[
						[-1000, -1000],
						[2000, 2000],
					]"
					:node-extent="[
						[-1000, -1000],
						[2000, 2000],
					]"
					:connection-mode="ConnectionMode.Loose"
					:connection-line-type="ConnectionLineType.SmoothStep"
					:connection-line-style="{ stroke: '#409eff', strokeWidth: 2 }"
					:default-edge-options="{ type: 'smoothstep' }"
					:apply-default="false"
					:auto-connect="false"
					:connect-on-click="false"
					:snap-to-grid="false"
					:snap-grid="[15, 15]"
					:only-render-visible-elements="true"
					:render-viewport="true"
					@node-click="onNodeClick"
					@node-double-click="onNodeDoubleClick"
					@node-mouse-enter="onNodeMouseEnter"
					@node-mouse-leave="onNodeMouseLeave"
					@edge-click="onEdgeClick"
					@edge-double-click="onEdgeDoubleClick"
					@edge-mouse-enter="onEdgeMouseEnter"
					@edge-mouse-leave="onEdgeMouseLeave"
					@pane-click="onPaneClick"
					@pane-context-menu="onPaneContextMenu"
					@move="onMove"
					@move-start="onMoveStart"
					@move-end="onMoveEnd"
					@selection-change="onSelectionChange"
					@edges-change="onEdgesChange"
					@nodes-change="onNodesChange"
				>
					<template #node-default="{ data }">
						<div class="custom-node" :class="getNodeClass(data)">
							<div class="node-content">
								<div class="node-header">
									<span class="node-title">{{ data.label }}</span>
									<span class="node-status" :class="getStatusClass(data.status)">
										{{ getStatusText(data.status) }}
									</span>
								</div>
								<div class="node-body" v-if="data.assignee || data.time">
									<div class="node-assignee" v-if="data.assignee">
										<el-icon>
											<User />
										</el-icon>
										{{ data.assignee }}
									</div>
									<div class="node-time" v-if="data.time">
										<el-icon>
											<Clock />
										</el-icon>
										{{ formatTime(data.time) }}
									</div>
								</div>
							</div>
						</div>
					</template>

					<template #node-input="{ data }">
						<div class="custom-node start-node">
							<div class="node-content">
								<div class="node-icon">
									<el-icon>
										<Document />
									</el-icon>
								</div>
								<div class="node-title">{{ data.label }}</div>
								<div class="node-time" v-if="data.time">{{ formatTime(data.time) }}</div>
							</div>
						</div>
					</template>

					<template #node-output="{ data }">
						<div class="custom-node end-node">
							<div class="node-content">
								<div class="node-icon">
									<el-icon>
										<CircleCheck />
									</el-icon>
								</div>
								<div class="node-title">{{ data.label }}</div>
								<div class="node-time" v-if="data.time">{{ formatTime(data.time) }}</div>
							</div>
						</div>
					</template>
				</VueFlow>
			</div>
			<div v-else class="empty-state">
				<el-icon><Document /></el-icon>
				<p>暂无流程数据</p>
			</div>
		</div>
	</div>
</template>

<script setup lang="ts">
import { computed, watch, ref, nextTick } from 'vue';
import { VueFlow, MarkerType, PanOnScrollMode, ConnectionMode, ConnectionLineType, useVueFlow } from '@vue-flow/core';
import { FullScreen, Plus, Minus, User, Clock, Document, CircleCheck } from '@element-plus/icons-vue';
import '@vue-flow/core/dist/style.css';

interface SimpleNode {
	id: string;
	label: string;
	type?: 'start' | 'process' | 'decision' | 'end';
	status?: 'completed' | 'processing' | 'pending' | 'error';
	description?: string;
	assignee?: string;
	time?: string;
	data?: any;
}

interface SimpleEdge {
	id: string;
	source: string;
	target: string;
	label?: string;
	status?: 'completed' | 'processing' | 'pending' | 'error';
	animated?: boolean;
	data?: any;
}

const props = withDefaults(
	defineProps<{
		title?: string;
		nodes?: SimpleNode[];
		edges?: SimpleEdge[];
		height?: number | string;
		showHeader?: boolean;
		nodesDraggable?: boolean;
		nodeSpacing?: number;
		levelSpacing?: number;
	}>(),
	{
		title: '流程图',
		nodes: () => [],
		edges: () => [],
		height: 400,
		showHeader: true,
		nodesDraggable: false,
		nodeSpacing: 200,
		levelSpacing: 120,
	}
);

const emit = defineEmits([
	'nodeClick',
	'edgeClick',
	'nodeDoubleClick',
	'nodeMouseEnter',
	'nodeMouseLeave',
	'edgeDoubleClick',
	'edgeMouseEnter',
	'edgeMouseLeave',
	'paneClick',
	'paneContextMenu',
	'move',
	'moveStart',
	'moveEnd',
	'selectionChange',
	'nodesInitialized',
	'edgesChange',
	'nodesChange',
]);

const chartWrapper = ref<HTMLElement>();
const vueFlowRef = ref<InstanceType<typeof VueFlow>>();
const zoomLevel = ref(1);
// 使用 Vue Flow 的 composable API
const { fitView: vueFlowFitView, zoomIn: vueFlowZoomIn, zoomOut: vueFlowZoomOut, zoomTo, setViewport, getViewport, toObject } = useVueFlow();

const layoutInfo = computed(() => {
	const nodeCount = props.nodes.length;
	return { nodeCount };
});

const containerStyle = computed(() => {
	const height = typeof props.height === 'number' ? `${props.height}px` : props.height;
	return { height, minHeight: '300px' };
});

const processedNodes = computed(() => {
	if (props.nodes.length === 0) return [];

	// 简单的网格布局
	const nodeWidth = 160;
	const nodeHeight = 80;
	const horizontalSpacing = 60;
	const verticalSpacing = 120;
	const maxNodesPerRow = 4;

	return props.nodes.map((node, index) => {
		const row = Math.floor(index / maxNodesPerRow);
		const col = index % maxNodesPerRow;

		const x = 100 + col * (nodeWidth + horizontalSpacing);
		const y = 100 + row * (nodeHeight + verticalSpacing);

		return {
			id: node.id,
			type: node.type === 'start' ? 'input' : node.type === 'end' ? 'output' : 'default',
			label: node.label,
			position: { x, y },
			data: node,
			draggable: props.nodesDraggable,
		};
	});
});

const processedEdges = computed(() => {
	if (props.edges.length === 0) return [];

	return props.edges.map((edge) => {
		const status = edge.status || 'pending';
		let strokeColor = '#dcdfe6';
		let strokeWidth = 1.5;
		const isDark = document.documentElement.classList.contains('dark');

		switch (status) {
			case 'completed':
				strokeColor = isDark ? '#85ce61' : '#67c23a';
				break;
			case 'processing':
				strokeColor = isDark ? '#5cadff' : '#409eff';
				break;
			case 'error':
				strokeColor = isDark ? '#ff7875' : '#f56c6c';
				break;
			case 'pending':
				strokeColor = isDark ? '#909399' : '#dcdfe6';
				break;
		}

		return {
			id: edge.id,
			source: edge.source,
			target: edge.target,
			type: 'smoothstep',
			animated: edge.animated || status === 'processing',
			style: {
				stroke: strokeColor,
				strokeWidth,
			},
			markerEnd: {
				type: MarkerType.ArrowClosed,
				width: 8,
				height: 8,
				color: strokeColor,
			},
		};
	});
});

// 控制函数 - 使用 Vue Flow 提供的方法
const handleFitView = async () => {
	await nextTick();
	try {
		// 使用 Vue Flow 的 fitView 方法
		vueFlowFitView({ padding: 0.1, duration: 300 });
		zoomLevel.value = 1;
	} catch (error) {
		console.warn('Fit view error:', error);
	}
};

const handleZoomIn = () => {
	try {
		// 使用 Vue Flow 的 zoomIn 方法
		vueFlowZoomIn({ duration: 200 });
		zoomLevel.value = Math.min(zoomLevel.value + 0.1, 4);
	} catch (error) {
		console.warn('Zoom in error:', error);
	}
};

const handleZoomOut = () => {
	try {
		// 使用 Vue Flow 的 zoomOut 方法
		vueFlowZoomOut({ duration: 200 });
		zoomLevel.value = Math.max(zoomLevel.value - 0.1, 0.2);
	} catch (error) {
		console.warn('Zoom out error:', error);
	}
};

// 其他控制方法
const resetViewport = () => {
	setViewport({ x: 0, y: 0, zoom: 1 });
	zoomLevel.value = 1;
};

const zoomToLevel = (zoom: number) => {
	zoomTo(zoom, { duration: 300 });
	zoomLevel.value = zoom;
};

// 节点事件处理
const onNodeClick = (event: any) => {
	emit('nodeClick', event);
};

const onNodeDoubleClick = (event: any) => {
	emit('nodeDoubleClick', event);
};

const onNodeMouseEnter = (event: any) => {
	emit('nodeMouseEnter', event);
};

const onNodeMouseLeave = (event: any) => {
	emit('nodeMouseLeave', event);
};

// 边事件处理
const onEdgeClick = (event: any) => {
	emit('edgeClick', event);
};

const onEdgeDoubleClick = (event: any) => {
	emit('edgeDoubleClick', event);
};

const onEdgeMouseEnter = (event: any) => {
	emit('edgeMouseEnter', event);
};

const onEdgeMouseLeave = (event: any) => {
	emit('edgeMouseLeave', event);
};

// 画布事件处理
const onPaneClick = (event: any) => {
	emit('paneClick', event);
};

const onPaneContextMenu = (event: any) => {
	emit('paneContextMenu', event);
};

// 移动事件处理
const onMove = (event: any) => {
	emit('move', event);
};

const onMoveStart = (event: any) => {
	emit('moveStart', event);
};

const onMoveEnd = (event: any) => {
	emit('moveEnd', event);
};

// 选择事件处理
const onSelectionChange = (event: any) => {
	emit('selectionChange', event);
};

// 数据变化事件处理
const onNodesInitialized = (event: any) => {
	emit('nodesInitialized', event);
};

const onEdgesChange = (event: any) => {
	emit('edgesChange', event);
};

const onNodesChange = (event: any) => {
	emit('nodesChange', event);
};

// 工具函数
const getNodeClass = (data: any) => {
	return {
		'node-completed': data.status === 'completed',
		'node-processing': data.status === 'processing',
		'node-pending': data.status === 'pending',
		'node-error': data.status === 'error',
	};
};

const getStatusClass = (status: string) => {
	return {
		'status-completed': status === 'completed',
		'status-processing': status === 'processing',
		'status-pending': status === 'pending',
		'status-error': status === 'error',
	};
};

const getStatusText = (status: string) => {
	const statusMap: Record<string, string> = {
		completed: '已完成',
		processing: '进行中',
		pending: '待处理',
		error: '异常',
	};
	return statusMap[status] || status;
};

const formatTime = (time: string) => {
	if (!time) return '';
	const date = new Date(time);
	return `${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
};

// 监听视图变化以更新缩放级别
watch(
	() => getViewport(),
	(viewport) => {
		if (viewport) {
			zoomLevel.value = viewport.zoom;
		}
	},
	{ deep: true }
);
</script>

<style scoped lang="scss">
.flow-chart-container {
	display: flex;
	flex-direction: column;
	background: #ffffff;
	border: 1px solid #e4e7ed;
	border-radius: 8px;
	overflow: hidden;
	box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);

	// 暗黑模式适配
	html.dark & {
		background: #121212;
		border: 1px solid #363637;
		box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
	}

	.flow-chart-header {
		background: #f8f9fa;
		border-bottom: 1px solid #e4e7ed;
		padding: 16px 20px;
		flex-shrink: 0;

		// 暗黑模式适配
		html.dark & {
			background: #1d1e1f;
			border-bottom: 1px solid #363637;
		}

		.header-content {
			display: flex;
			justify-content: space-between;
			align-items: center;
		}

		.header-left {
			display: flex;
			align-items: center;
			gap: 16px;

			.chart-title {
				margin: 0;
				font-size: 16px;
				font-weight: 600;
				color: #303133;

				// 暗黑模式适配
				html.dark & {
					color: #e5eaf3;
				}
			}

			.chart-info {
				display: flex;
				gap: 8px;

				.info-badge {
					background: #ecf5ff;
					color: #409eff;
					padding: 4px 8px;
					border-radius: 12px;
					font-size: 12px;
					font-weight: 500;

					// 暗黑模式适配
					html.dark & {
						background: rgba(64, 158, 255, 0.1);
					}

					&.draggable-hint {
						background: #f0f9eb;
						color: #67c23a;
						display: flex;
						align-items: center;
						gap: 4px;

						// 暗黑模式适配
						html.dark & {
							background: rgba(103, 194, 58, 0.1);
						}

						.el-icon {
							font-size: 12px;
						}
					}
				}
			}
		}

		.header-right {
			display: flex;
			align-items: center;
			gap: 12px;

			.zoom-level {
				font-size: 13px;
				color: #666666;
				background: #f5f7fa;
				padding: 4px 8px;
				border-radius: 4px;
				min-width: 50px;
				text-align: center;
				font-weight: 500;

				// 暗黑模式适配
				html.dark & {
					color: #a3a6ad;
					background: #2a2a2b;
				}
			}
		}
	}

	.flow-chart-wrapper {
		flex: 1;
		position: relative;
		background: #fafbfc;
		overflow: hidden;
		min-height: 300px;

		// 暗黑模式适配
		html.dark & {
			background: #121212;
		}

		.flow-chart-inner {
			width: 100%;
			height: 100%;
			position: relative;
		}

		.empty-state {
			display: flex;
			flex-direction: column;
			align-items: center;
			justify-content: center;
			height: 100%;
			color: #64748b;

			// 暗黑模式适配
			html.dark & {
				color: #909399;
			}

			.el-icon {
				font-size: 48px;
				margin-bottom: 16px;
				color: #94a3b8;

				// 暗黑模式适配
				html.dark & {
					color: #606266;
				}
			}

			p {
				margin: 0;
				font-size: 14px;
				font-weight: 500;
			}
		}
	}

	.flow-chart {
		width: 100%;
		height: 100%;
	}
}

// 美化的节点样式 - 无边框卡片设计
:deep(.custom-node) {
	background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
	border: none !important;
	outline: none !important;
	border-radius: 12px;
	padding: 16px 20px;
	min-width: 160px;
	width: 160px;
	min-height: 80px;
	height: auto;
	box-shadow:
		0 4px 16px rgba(0, 0, 0, 0.08),
		0 2px 8px rgba(0, 0, 0, 0.04);
	transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
	cursor: pointer;
	position: relative;
	overflow: hidden;

	// 暗黑模式适配
	html.dark & {
		background: linear-gradient(135deg, #1d1e1f 0%, #18181a 100%);
		box-shadow:
			0 4px 16px rgba(0, 0, 0, 0.2),
			0 2px 8px rgba(0, 0, 0, 0.15);
		color: #e5eaf3;
		border: 1px solid rgba(255, 255, 255, 0.05) !important;
	}

	// 添加微妙的内阴影效果
	&::before {
		content: '';
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background: linear-gradient(135deg, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.2) 100%);
		border-radius: 12px;
		pointer-events: none;

		// 暗黑模式适配
		html.dark & {
			background: linear-gradient(135deg, rgba(40, 40, 40, 0.6) 0%, rgba(30, 30, 30, 0.2) 100%);
		}
	}

	&:hover {
		box-shadow:
			0 8px 24px rgba(64, 158, 255, 0.12),
			0 4px 12px rgba(64, 158, 255, 0.08);
		transform: translateY(-2px) scale(1.02);
		background: linear-gradient(135deg, #ffffff 0%, #f0f8ff 100%);

		// 暗黑模式适配
		html.dark & {
			background: linear-gradient(135deg, #1d1e1f 0%, #1a212c 100%);
			box-shadow:
				0 8px 24px rgba(64, 158, 255, 0.3),
				0 4px 12px rgba(64, 158, 255, 0.2);
			color: #e5eaf3;
		}
	}

	&.node-completed {
		background: linear-gradient(135deg, #f0f9eb 0%, #e8f5e8 100%);
		box-shadow:
			0 4px 16px rgba(103, 194, 58, 0.15),
			0 2px 8px rgba(103, 194, 58, 0.08);

		// 暗黑模式适配
		html.dark & {
			background: linear-gradient(135deg, rgba(103, 194, 58, 0.25) 0%, rgba(103, 194, 58, 0.15) 100%);
			box-shadow:
				0 4px 16px rgba(103, 194, 58, 0.2),
				0 2px 8px rgba(103, 194, 58, 0.1);
			color: #e5eaf3;
			border: 1px solid rgba(103, 194, 58, 0.3) !important;
		}

		&:hover {
			background: linear-gradient(135deg, #e8f5e8 0%, #d4edda 100%);
			box-shadow:
				0 8px 24px rgba(103, 194, 58, 0.2),
				0 4px 12px rgba(103, 194, 58, 0.12);

			// 暗黑模式适配
			html.dark & {
				background: linear-gradient(135deg, rgba(103, 194, 58, 0.2) 0%, rgba(103, 194, 58, 0.15) 100%);
				box-shadow:
					0 8px 24px rgba(103, 194, 58, 0.25),
					0 4px 12px rgba(103, 194, 58, 0.15);
			}
		}
	}

	&.node-processing {
		background: linear-gradient(135deg, #ecf5ff 0%, #e1f0ff 100%);
		box-shadow:
			0 4px 16px rgba(64, 158, 255, 0.15),
			0 2px 8px rgba(64, 158, 255, 0.08);

		// 暗黑模式适配
		html.dark & {
			background: linear-gradient(135deg, rgba(64, 158, 255, 0.25) 0%, rgba(64, 158, 255, 0.15) 100%);
			box-shadow:
				0 4px 16px rgba(64, 158, 255, 0.2),
				0 2px 8px rgba(64, 158, 255, 0.1);
			color: #e5eaf3;
			border: 1px solid rgba(64, 158, 255, 0.3) !important;
		}

		&:hover {
			background: linear-gradient(135deg, #e1f0ff 0%, #cce7ff 100%);
			box-shadow:
				0 8px 24px rgba(64, 158, 255, 0.2),
				0 4px 12px rgba(64, 158, 255, 0.12);

			// 暗黑模式适配
			html.dark & {
				background: linear-gradient(135deg, rgba(64, 158, 255, 0.2) 0%, rgba(64, 158, 255, 0.15) 100%);
				box-shadow:
					0 8px 24px rgba(64, 158, 255, 0.25),
					0 4px 12px rgba(64, 158, 255, 0.15);
			}
		}
	}

	&.node-pending {
		background: linear-gradient(135deg, #fdf6ec 0%, #faebd7 100%);
		box-shadow:
			0 4px 16px rgba(230, 162, 60, 0.15),
			0 2px 8px rgba(230, 162, 60, 0.08);

		// 暗黑模式适配
		html.dark & {
			background: linear-gradient(135deg, rgba(230, 162, 60, 0.25) 0%, rgba(230, 162, 60, 0.15) 100%);
			box-shadow:
				0 4px 16px rgba(230, 162, 60, 0.2),
				0 2px 8px rgba(230, 162, 60, 0.1);
			color: #e5eaf3;
			border: 1px solid rgba(230, 162, 60, 0.3) !important;
		}

		&:hover {
			background: linear-gradient(135deg, #faebd7 0%, #f5deb3 100%);
			box-shadow:
				0 8px 24px rgba(230, 162, 60, 0.2),
				0 4px 12px rgba(230, 162, 60, 0.12);

			// 暗黑模式适配
			html.dark & {
				background: linear-gradient(135deg, rgba(230, 162, 60, 0.2) 0%, rgba(230, 162, 60, 0.15) 100%);
				box-shadow:
					0 8px 24px rgba(230, 162, 60, 0.25),
					0 4px 12px rgba(230, 162, 60, 0.15);
			}
		}
	}

	&.node-error {
		background: linear-gradient(135deg, #fef0f0 0%, #fde8e8 100%);
		box-shadow:
			0 4px 16px rgba(245, 108, 108, 0.15),
			0 2px 8px rgba(245, 108, 108, 0.08);

		// 暗黑模式适配
		html.dark & {
			background: linear-gradient(135deg, rgba(245, 108, 108, 0.25) 0%, rgba(245, 108, 108, 0.15) 100%);
			box-shadow:
				0 4px 16px rgba(245, 108, 108, 0.2),
				0 2px 8px rgba(245, 108, 108, 0.1);
			color: #e5eaf3;
			border: 1px solid rgba(245, 108, 108, 0.3) !important;
		}

		&:hover {
			background: linear-gradient(135deg, #fde8e8 0%, #fbd5d5 100%);
			box-shadow:
				0 8px 24px rgba(245, 108, 108, 0.2),
				0 4px 12px rgba(245, 108, 108, 0.12);

			// 暗黑模式适配
			html.dark & {
				background: linear-gradient(135deg, rgba(245, 108, 108, 0.2) 0%, rgba(245, 108, 108, 0.15) 100%);
				box-shadow:
					0 8px 24px rgba(245, 108, 108, 0.25),
					0 4px 12px rgba(245, 108, 108, 0.15);
			}
		}
	}

	.node-content {
		width: 100%;
		position: relative;
		z-index: 1;

		.node-header {
			display: flex;
			align-items: center;
			justify-content: space-between;
			margin-bottom: 10px;

			.node-title {
				font-size: 15px;
				font-weight: 700;
				color: #1a1a1a;
				line-height: 1.3;
				overflow: hidden;
				text-overflow: ellipsis;
				white-space: nowrap;
				flex: 1;
				text-align: left;
				text-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);

				// 暗黑模式适配
				html.dark & {
					color: #e5eaf3;
					text-shadow: none;
				}
			}

			.node-status {
				font-size: 10px;
				font-weight: 600;
				padding: 4px 8px;
				border-radius: 12px;
				white-space: nowrap;
				margin-left: 8px;
				text-transform: uppercase;
				letter-spacing: 0.5px;
				box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
				backdrop-filter: blur(4px);

				// 暗黑模式适配
				html.dark & {
					box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
				}

				&.status-completed {
					background: linear-gradient(135deg, #67c23a 0%, #5daf35 100%);
					color: #ffffff;
					box-shadow: 0 2px 8px rgba(103, 194, 58, 0.3);

					// 暗黑模式适配
					html.dark & {
						box-shadow: 0 2px 8px rgba(103, 194, 58, 0.4);
					}
				}

				&.status-processing {
					background: linear-gradient(135deg, #409eff 0%, #3a8ee6 100%);
					color: #ffffff;
					box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);

					// 暗黑模式适配
					html.dark & {
						box-shadow: 0 2px 8px rgba(64, 158, 255, 0.4);
					}
				}

				&.status-pending {
					background: linear-gradient(135deg, #e6a23c 0%, #d9941f 100%);
					color: #ffffff;
					box-shadow: 0 2px 8px rgba(230, 162, 60, 0.3);

					// 暗黑模式适配
					html.dark & {
						box-shadow: 0 2px 8px rgba(230, 162, 60, 0.4);
					}
				}

				&.status-error {
					background: linear-gradient(135deg, #f56c6c 0%, #f25555 100%);
					color: #ffffff;
					box-shadow: 0 2px 8px rgba(245, 108, 108, 0.3);

					// 暗黑模式适配
					html.dark & {
						box-shadow: 0 2px 8px rgba(245, 108, 108, 0.4);
					}
				}
			}
		}

		.node-body {
			display: flex;
			flex-direction: column;
			gap: 6px;
			border: none;

			.node-assignee,
			.node-time {
				display: flex;
				align-items: center;
				gap: 6px;
				font-size: 12px;
				line-height: 1.4;
				padding: 2px 0;
				border-radius: 4px;
				transition: all 0.2s ease;

				.el-icon {
					font-size: 13px;
					opacity: 0.8;
				}
			}

			.node-assignee {
				color: #409eff;
				font-weight: 600;
				background: rgba(64, 158, 255, 0.05);
				padding: 3px 8px;
				border-radius: 6px;

				// 暗黑模式适配
				html.dark & {
					background: rgba(64, 158, 255, 0.1);
				}

				.el-icon {
					color: #409eff;
				}
			}

			.node-time {
				color: #666666;
				font-weight: 500;
				background: rgba(0, 0, 0, 0.03);
				padding: 3px 8px;
				border-radius: 6px;

				// 暗黑模式适配
				html.dark & {
					color: #a3a6ad;
					background: rgba(255, 255, 255, 0.05);
				}

				.el-icon {
					color: #999999;

					// 暗黑模式适配
					html.dark & {
						color: #a3a6ad;
					}
				}
			}
		}
	}

	&.start-node,
	&.end-node {
		min-width: 140px;
		width: 140px;
		height: 70px;
		border-radius: 35px;
		display: flex;
		align-items: center;
		justify-content: center;
		box-shadow:
			0 6px 20px rgba(0, 0, 0, 0.1),
			0 3px 10px rgba(0, 0, 0, 0.05);

		// 暗黑模式适配
		html.dark & {
			box-shadow:
				0 6px 20px rgba(0, 0, 0, 0.25),
				0 3px 10px rgba(0, 0, 0, 0.15);
		}

		&:hover {
			transform: translateY(-2px) scale(1.05);
			box-shadow:
				0 10px 30px rgba(0, 0, 0, 0.15),
				0 5px 15px rgba(0, 0, 0, 0.08);

			// 暗黑模式适配
			html.dark & {
				box-shadow:
					0 10px 30px rgba(0, 0, 0, 0.3),
					0 5px 15px rgba(0, 0, 0, 0.2);
			}
		}

		.node-content {
			text-align: center;
			position: relative;
			z-index: 1;

			.node-icon {
				margin-bottom: 6px;

				.el-icon {
					font-size: 22px;
					filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));

					// 暗黑模式适配
					html.dark & {
						filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
					}
				}
			}

			.node-title {
				font-size: 13px;
				font-weight: 700;
				margin: 0;
				text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
				letter-spacing: 0.3px;

				// 暗黑模式适配
				html.dark & {
					text-shadow: none;
				}
			}

			.node-time {
				font-size: 10px;
				margin-top: 4px;
				opacity: 0.8;
				font-weight: 500;
			}
		}
	}

	&.start-node {
		background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);

		// 暗黑模式适配
		html.dark & {
			background: linear-gradient(135deg, #2a2a2b 0%, #1d1e1f 100%);
			color: #e5eaf3;
			border: 1px solid rgba(255, 255, 255, 0.08) !important;
		}

		.node-content {
			.node-icon .el-icon {
				color: #6c757d;

				// 暗黑模式适配
				html.dark & {
					color: #a3a6ad;
				}
			}

			.node-title {
				color: #495057;

				// 暗黑模式适配
				html.dark & {
					color: #e5eaf3;
				}
			}

			.node-time {
				color: #6c757d;

				// 暗黑模式适配
				html.dark & {
					color: #a3a6ad;
				}
			}
		}

		&:hover {
			background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);

			// 暗黑模式适配
			html.dark & {
				background: linear-gradient(135deg, #2a2a2b 0%, #252526 100%);
			}
		}
	}

	&.end-node {
		background: linear-gradient(135deg, #d1edcc 0%, #c3e6be 100%);

		// 暗黑模式适配
		html.dark & {
			background: linear-gradient(135deg, rgba(103, 194, 58, 0.2) 0%, rgba(103, 194, 58, 0.15) 100%);
			color: #e5eaf3;
			border: 1px solid rgba(103, 194, 58, 0.25) !important;
		}

		.node-content {
			.node-icon .el-icon {
				color: #28a745;
			}

			.node-title {
				color: #155724;

				// 暗黑模式适配
				html.dark & {
					color: #67c23a;
				}
			}

			.node-time {
				color: #28a745;
			}
		}

		&:hover {
			background: linear-gradient(135deg, #c3e6be 0%, #b1dfbb 100%);

			// 暗黑模式适配
			html.dark & {
				background: linear-gradient(135deg, rgba(103, 194, 58, 0.2) 0%, rgba(103, 194, 58, 0.15) 100%);
			}
		}
	}
}

// Vue Flow 样式修复和优化
:deep(.vue-flow) {
	width: 100%;
	height: 100%;
}

:deep(.vue-flow__renderer) {
	width: 100%;
	height: 100%;
}

:deep(.vue-flow__container) {
	width: 100%;
	height: 100%;
}

// 移除Vue Flow所有默认的节点边框
:deep(.vue-flow__node-default),
:deep(.vue-flow__node-input),
:deep(.vue-flow__node-output) {
	border: none !important;
	outline: none !important;
	box-shadow: none !important;
}

// 隐藏选中时的边框和控制点
:deep(.vue-flow__node.selected) {
	.vue-flow__node-default,
	.vue-flow__node-input,
	.vue-flow__node-output {
		box-shadow: none !important;
		outline: none !important;
		border: none !important;
	}
}

// 强制移除所有Vue Flow节点的边框
:deep(.vue-flow__node) {
	border: none !important;
	outline: none !important;

	.vue-flow__node-default,
	.vue-flow__node-input,
	.vue-flow__node-output {
		border: none !important;
		outline: none !important;
		box-shadow: none !important;
	}
}

// 隐藏节点的选择框
:deep(.vue-flow__nodesselection) {
	display: none !important;
}

// 隐藏节点的控制点
:deep(.vue-flow__handle) {
	display: none !important;
}

// 美化选中状态的节点样式
:deep(.vue-flow__node.selected .custom-node) {
	border: none !important;
	outline: none !important;
	box-shadow:
		0 0 0 3px rgba(64, 158, 255, 0.3),
		0 0 20px rgba(64, 158, 255, 0.2),
		0 8px 32px rgba(64, 158, 255, 0.15) !important;
	transform: translateY(-3px) scale(1.03) !important;
	z-index: 10 !important;

	// 暗黑模式适配
	html.dark & {
		box-shadow:
			0 0 0 3px rgba(64, 158, 255, 0.5),
			0 0 20px rgba(64, 158, 255, 0.3),
			0 8px 32px rgba(64, 158, 255, 0.25) !important;
		border: 1px solid rgba(64, 158, 255, 0.6) !important;
		background: linear-gradient(135deg, rgba(64, 158, 255, 0.15) 0%, rgba(64, 158, 255, 0.05) 100%);
	}
}

// 简洁的连线样式
:deep(.vue-flow__edge) {
	.vue-flow__edge-path {
		stroke-width: 1.5px;
		transition: stroke-width 0.2s ease;
	}

	&:hover .vue-flow__edge-path {
		stroke-width: 2px;
	}

	&.animated .vue-flow__edge-path {
		stroke-dasharray: 5;
		animation: dash 1s linear infinite;
	}

	&.selected .vue-flow__edge-path {
		stroke-width: 1.5px !important;
	}

	// 暗黑模式适配
	html.dark & {
		.vue-flow__edge-path {
			stroke-opacity: 0.8;
			filter: drop-shadow(0 0 3px rgba(255, 255, 255, 0.1));
		}

		&.animated .vue-flow__edge-path {
			stroke-dasharray: 5;
			animation: dash 1s linear infinite;
			stroke-opacity: 0.9;
		}

		&.selected .vue-flow__edge-path {
			stroke-width: 2px !important;
			filter: drop-shadow(0 0 5px rgba(64, 158, 255, 0.4));
		}
	}
}

@keyframes dash {
	to {
		stroke-dashoffset: -10;
	}
}

// 响应式设计
@media (max-width: 768px) {
	.flow-chart-container {
		.flow-chart-header {
			padding: 12px 16px;

			.header-content {
				flex-direction: column;
				gap: 12px;
				align-items: flex-start;
			}

			.header-left {
				width: 100%;
				justify-content: space-between;

				.chart-info {
					flex-wrap: wrap;
				}
			}
		}
	}

	:deep(.custom-node) {
		min-width: 140px;
		padding: 10px;

		.node-content {
			.node-header {
				flex-direction: column;
				align-items: flex-start;
				gap: 4px;

				.node-title {
					font-size: 13px;
				}
			}

			.node-body {
				.node-assignee,
				.node-time {
					font-size: 11px;
				}
			}
		}

		&.start-node,
		&.end-node {
			min-width: 100px;

			.node-content {
				.node-icon .el-icon {
					font-size: 20px;
				}

				.node-title {
					font-size: 13px;
				}
			}
		}
	}
}
</style>
